#include "domain.h"
#include "sudoku.h"
#include "cell.h"

#include <assert.h>

void Domain::registerCell(Cell* p_cell)
{
    assert(p_cell != NULL);
    m_cells.push_back(p_cell);
}

bool Domain::promoteUniqueCandidate(int candidate)
{
    if (candidate < 1 || candidate > DOMAIN_SIZE)
        return false;

    assert(m_cells.size() == DOMAIN_SIZE);

    int value;
    int candidate_count = 0;
    Cell* p_cell_with_unique_candidate = NULL;
    for (int i = 0; i < DOMAIN_SIZE; i++)
    {
        Cell* p_cell = m_cells[i];
        if (p_cell->getValue(value))
            if (value == candidate)
                return false;

        if (p_cell->hasCandidate(candidate))
        {
            p_cell_with_unique_candidate = p_cell;
            candidate_count++;
        }
    }

    if (candidate_count == 1)
    {
        assert(p_cell_with_unique_candidate != NULL);
        bool sv = p_cell_with_unique_candidate->setValue(candidate);
        assert(sv == true);
        return true;
    }
    else
        return false;
}

int Domain::deleteCandidatesByValue(int v)
{
    bool has_value = false;
    for (unsigned int i = 0; i < m_cells.size(); i++)
    {
        if (m_cells[i]->hasValue(v))
        {
            has_value = true;
            break;
        }
    }

    int deleted = 0;
    if (has_value == false)
        return deleted;

    for (unsigned int i = 0; i < m_cells.size(); i++)
    {
        if (m_cells[i]->deleteCandidate(v) == true)
            deleted++;
    }

    return deleted;
}

bool Domain::runUnitTest()
{
    Domain domain;
    for (int i = 0; i < DOMAIN_SIZE; i++)
    {
        Cell* p_cell = new Cell();
        domain.registerCell(p_cell);
    }

    // At this stage, all cells have fully populated candidate lists,
    // so promoteUniqueCandidate should fail
    bool retval = domain.promoteUniqueCandidate(1);
    if (retval != false)
        return false;

    // No cell has value 1, so this method should return 0
    int deleted = domain.deleteCandidatesByValue(1);
    if (deleted != 0)
        return false;

    // We set the value of one cell to 1
    if (domain.m_cells[0]->setValue(1) != true)
        return false;

    // Now candidate 1 should be deleted from all other cells,
    // so return value is one less than the largest possible value
    deleted = domain.deleteCandidatesByValue(1);
    if (deleted != DOMAIN_SIZE - 1)
        return false;

    return true;
}